import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.Logger;

//@author A0105195J

public class TimeParser {
	private static final int END_INDEX_OF_DAY = 3;
	private static final int START_INDEX_OF_DAY = 0;
	private static final int END_INDEX_OF_DATE = 11;
	private static final int START_INDEX_OF_MONTH = 4;
	private static final int START_INDEX_OF_YEAR = 24;
	private static final int END_INDEX_OF_TIME = 16;
	private static final int START_INDEX_OF_TIME = 10;
	private static final int INDEX2_OF_TODAY_TASK = 13;
	private static final int INDEX1_OF_TODAY_TASK = 12;
	private static final int CODE_FOR_DATE_WITH_TIME = 0;
	private static final int CODE_FOR_DATE_WITHOUT_TIME = 1;
	private static final int DEFAULT_YEAR_FOR_CALENDAR = 1970;
	private static final int CURRENT_MILLENIUM = 3;
	private static final int YEARS_IN_MILLENIUM = 1000;

	// List of date formats (with time) supported
	static String[] dateFormatsWithTime = { "dd MMMMM hhaaa",
			"dd MMMMM yy hhaaa", "MMMMM dd hhaaa", "MMMMM dd yy hhaaa",
			"dd/MM hhaaa", "dd/MM/yyyy hhaaa", "dd MMMMM h.mmaaa",
			"dd MMMMM yy hh.mmaaa", "MMMMM dd yy h.mmaaa", "MMMMM dd h.mmaaa",
			"dd/MM h.mmaaa", "dd/MM/yyyy h.mmaaa", "hhaaa", "hh.mmaaa" };

	// List of date formats (without time) supported
	static String[] dateFormatsWithoutTime = { "dd MMMMM yy", "dd MMMMM",
			"MMMMM dd yy", "MMMMM dd", "dd/MM/yyyy", "dd/MM" };

	private static Logger logger = Logger
			.getLogger("Log for Date and Time Parser");

	public static void main(String[] args) {

	}

	public static Date parseTime(String time) {

		Date dateObject = null;
		String dateInString = formatString(time);
		boolean isHit = false;

		for (int i = 0; i < dateFormatsWithTime.length && !isHit; i++)
			try {
				dateObject = convert_to_date(dateInString, i,
						CODE_FOR_DATE_WITH_TIME);
				isHit = true; // found a hit! the task is a valid event task
				logger.info("Match found with " + dateFormatsWithTime[i] + "\n");

			} catch (ParseException e) {
				logger.info("Testing timed: " + "Format " + (i + 1)
						+ " failed, testing Format " + (i + 2));

			}
		if (!isHit) { // the date doesn't have a time.

			for (int i = 0; i < dateFormatsWithoutTime.length && !isHit; i++)
				try {

					dateObject = convert_to_date(dateInString, i,
							CODE_FOR_DATE_WITHOUT_TIME);
					isHit = true;
					logger.info("Match found with " + dateFormatsWithoutTime[i]
							+ "\n");

				} catch (ParseException e) {
					logger.info("Testing untimed: " + "Format " + (i + 1)
							+ " failed, testing Format " + (i + 2));

				}
		}
		// To be used only while running JUnit tests, change return type to
		// String

		/*
		 * if (dateObject == null){ logger.info("No Match found!\n"); return
		 * "Error: Invalid Format\n"; } return printDate(dateObject);
		 */

		// To be used in normal cases
		logger.info("No Match found!\n");
		return (dateObject);
	}

	public static Date convert_to_date(String dateInString, int index,
			int dateType) throws ParseException {
		Date D;
		SimpleDateFormat formatter;
		if (dateType == CODE_FOR_DATE_WITH_TIME)
			formatter = new SimpleDateFormat(dateFormatsWithTime[index]);
		else
			formatter = new SimpleDateFormat(dateFormatsWithoutTime[index]);
		D = parseDate(dateInString, formatter, index);
		return D;
	}

	public static String formatString(String dateInString) {
		dateInString = dateInString.replace("st", "");
		dateInString = dateInString.replace("nd", "");
		dateInString = dateInString.replace("rd", "");
		dateInString = dateInString.replace("th", "");
		return dateInString;
	}

	public static Date parseDate(String dateInString,
			SimpleDateFormat formatter, int index) throws ParseException {
		Date date = formatter.parse(dateInString);
		Calendar c = Calendar.getInstance(), temp = Calendar.getInstance();
		int currentYear = c.get(Calendar.YEAR);
		c.setTime(date);
		if (index == INDEX1_OF_TODAY_TASK || index == INDEX2_OF_TODAY_TASK) {
			c.set(Calendar.MONTH, temp.get(Calendar.MONTH));
			c.set(Calendar.DAY_OF_MONTH, temp.get(Calendar.DAY_OF_MONTH));
		}
		if (c.get(Calendar.YEAR) == DEFAULT_YEAR_FOR_CALENDAR) {
			c.set(Calendar.YEAR, currentYear);
		}
		if (c.get(Calendar.YEAR) < 100) {
			c.set(Calendar.YEAR, YEARS_IN_MILLENIUM * (CURRENT_MILLENIUM - 1)
					+ c.get(Calendar.YEAR));
		}
		date = c.getTime();

		return date;

	}

	public static String printDate(Date date) {
		String print = date.toString();

		return (printDay(print) + ", " + printMonthAndDate(print)
				+ printYear(print) + printTime(print));

		// To be used while running JUnit tests
		// return (printMonthAndDate(print) + printYear(print) +
		// printTime(print));
	}

	public static String printTime(String print) {
		return print.substring(START_INDEX_OF_TIME, END_INDEX_OF_TIME);
	}

	public static String printYear(String print) {
		return print.substring(START_INDEX_OF_YEAR);
	}

	public static String printMonthAndDate(String print) {
		return print.substring(START_INDEX_OF_MONTH, END_INDEX_OF_DATE);
	}

	public static String printDay(String print) {
		return print.substring(START_INDEX_OF_DAY, END_INDEX_OF_DAY);
	}

}